//
// Created by yunlang on 2021/12/1.
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
#include "a.h"
#include "FileIO.h"
#include "FileEncode.h"
#include "menu.h"
using namespace std;
const unsigned int FileIO::FMAX_BLOCK_BYTES = 10240000;
const unsigned int FileIO::EncodeFileInfoLength = 8;
const unsigned int FileIO::FileTypeInfoLength = 1;
FILETYPE GetTextFileType(const string& strFileName)
{
    FILETYPE filetype = ANSI;
    ifstream file;
    file.open(strFileName.c_str(),ios_base::in);
    bool bUnicodeFile = false;
    if( file.good() )
    {
        char szFlag[2] = {0};
        file.read(szFlag,sizeof(char) * 2);
        if( (unsigned char)szFlag[0] == 0xFF && (unsigned char)szFlag[1] == 0xFE )
            filetype = UNICODE;
    }
    file.close();
    return filetype;
}

File *FileIO::readFromFile(const string &filename)
{
    string s = "/home/yunlang/work/CLionProjects/FileArchiver/build/" + filename;
    FILE * fp = fopen(s.c_str(),"rb");
    if( fp == nullptr )
    {
        printf("no file\n");
        getchar();
        getchar();
        system("clear");
        menu();
        return nullptr;
    }
    else
    {
        FILETYPE fileType = GetTextFileType(filename);
        auto fileData = new unsigned char [FMAX_BLOCK_BYTES+1];
        unsigned int dataBitSize = fread(fileData,sizeof(unsigned char),FMAX_BLOCK_BYTES,fp);
        fclose(fp);
        File * filePtr = new File(fileData,dataBitSize,fileType);
        return filePtr;
    }
}
void FileIO::writeToZip(FILETYPE filetype, const string &filename,
                        const unordered_map<unsigned char, unsigned int> &weightMap,
                        const unsigned char *encodeData,
                        unsigned int encodeDataSize, unsigned int encodeDataBitSize)
{
    string s = "/home/yunlang/work/CLionProjects/FileArchiver/build/" + filename;
    FILE* fp = fopen(s.c_str(), "wb");
    if(fp == nullptr)
    {
    }
    //fwrite(a,sizeof(unsigned char),FileTypeInfoLength,fp);


    auto weightMapValCount = static_cast<unsigned int>(weightMap.size());
    auto encodeFileInfoPtr = new unsigned char[EncodeFileInfoLength];
    for (int byteIndex = 0; byteIndex < 4; byteIndex++)
    {
        encodeFileInfoPtr[byteIndex] =
                static_cast<unsigned char>(0xff & (encodeDataBitSize >> (byteIndex * 8)));
        encodeFileInfoPtr[byteIndex + 4] =
                static_cast<unsigned char>(0xff & (weightMapValCount >> (byteIndex * 8)));
    }
    fwrite(encodeFileInfoPtr, sizeof(unsigned char), EncodeFileInfoLength, fp);



    //Map convert
    const unsigned long long weightMapArrSize = weightMapValCount * FileEncode::WeightMapElementSize;
    auto *weightMapArr = new unsigned char[weightMapArrSize];
    int elementIndex = 0;
    for (auto& element: weightMap)
    {
        weightMapArr[elementIndex * FileEncode::WeightMapElementSize] = element.first;
        fflush(stdout);
        for (int byteIndex = 0; byteIndex < 4; byteIndex++)
        {
            weightMapArr[elementIndex * FileEncode::WeightMapElementSize + byteIndex + 1] =
                    static_cast<unsigned char>(0xff & (element.second >> (byteIndex * 8)));
        }
        elementIndex++;
    }

    //
    cout << encodeDataSize << endl;
    fwrite(weightMapArr,sizeof(unsigned char),weightMapArrSize,fp);
    fwrite(encodeData,sizeof(unsigned char),encodeDataSize,fp);
    delete [] encodeFileInfoPtr;
    delete [] weightMapArr;
    fclose(fp);
}
FileEncode* FileIO::readFromZip(const string& filename)
{
    string s = "/home/yunlang/work/CLionProjects/FileArchiver/build/" + filename;
    FILE *fp = fopen(s.c_str(),"rb");
    if(fp == nullptr)
    {
        printf("no file\n");
        getchar();
        getchar();
        system("clear");
        menu();
    }
        ;
    auto fileInfoPtr = new unsigned char[FileTypeInfoLength];
    *fileInfoPtr = '1';
    //fread(fileInfoPtr,sizeof(unsigned char),FileTypeInfoLength,fp);
    auto encodeFileInfoPtr = new unsigned char[EncodeFileInfoLength];
    fread(encodeFileInfoPtr,sizeof(unsigned char),EncodeFileInfoLength,fp);
    unsigned int dataBitSize = *reinterpret_cast<unsigned int *>(encodeFileInfoPtr);
    unsigned int weightMapValCount = *reinterpret_cast<unsigned int *>(encodeFileInfoPtr + EncodeFileInfoLength / 2);
    delete [] encodeFileInfoPtr;

    const size_t weightMapDataSize = weightMapValCount * FileEncode::WeightMapElementSize;
    auto weightMapDataPtr = new unsigned char[weightMapDataSize + 1];
    fread(weightMapDataPtr,sizeof(unsigned char),weightMapDataSize,fp);
    unsigned int dataSize = dataBitSize / 8 + (dataBitSize % 8 == 0 ? 0 : 1);
    auto dataPtr = new unsigned char[dataSize + 1];
    memset(dataPtr,'\0',dataSize + 1);
    fread(dataPtr,sizeof(unsigned char),dataSize,fp);
    fclose(fp);
    auto encodeFilePtr = new FileEncode(fileInfoPtr, weightMapDataPtr, dataPtr, dataBitSize, weightMapValCount);
    return encodeFilePtr;
}
void FileIO::writeToFile(const string &filename, const unsigned char *fileInfo, const unsigned char *decodeDataPtr,
                         const unsigned int decodeDataBits)
{
    string s = "/home/yunlang/work/CLionProjects/FileArchiver/build/" + filename;
    FILE * fp = fopen(s.c_str(),"wb");
    if(fp == nullptr)
    {
    }
    FILETYPE filetype = (fileInfo == 0) ? ANSI : UNICODE;
    if(filetype == UNICODE)
    {

        unsigned char szFlag[2] = {static_cast<unsigned char>(0xFF),static_cast<unsigned char>(0xFE)};
        //fwrite(szFlag,sizeof(unsigned char),2,fp);
    }
    else
        ;
    const unsigned int rawSize = decodeDataBits / 8 + ( (decodeDataBits % 8 == 0) ? 0 : 1 );
    fwrite(decodeDataPtr,sizeof(unsigned char),decodeDataBits,fp);
    fclose(fp);
}
//i
// Created by yunlang on 2021/12/1.
//
